package AnalizadorSintactico;

import java.util.ArrayList;

import javax.swing.tree.DefaultMutableTreeNode;

import AnalizadorLexico.CategoriaLexica;
import AnalizadorLexico.Lexema;
import AnalizadorSemantico.SimboloCampo;
import AnalizadorSemantico.SimboloMetodo;
import AnalizadorSemantico.UtilidadesSemanticas;

public class Factor implements CategoriaLexica {

	private Lexema factor;
	private ExpresionAritmetica expresion;
	private LlamadaAMetodo llamada;
	private ArrayList<SimboloCampo> tablaCampos;
	private String ambito;
	private ArrayList<SimboloMetodo> tablaMetodos;

	public void setAmbito(String ambito) {
		this.ambito = ambito;
	}

	public void setTablaCampos(ArrayList<SimboloCampo> tablaCampos) {
		this.tablaCampos = tablaCampos;
	}

	public Factor(Lexema factor) {
		this.factor = factor;
	}

	public Factor(ExpresionAritmetica expresion) {
		this.expresion = expresion;
	}

	public Factor(LlamadaAMetodo llamada) {
		this.llamada = llamada;
	}

	@Override
	public String toString() {
		String fact = "";
		if (factor != null) {
			fact = factor.getLexema();
		}
		if (expresion != null) {
			fact = expresion.toString();
		}
		if (llamada != null) {
			fact = llamada.toString();
		}
		return fact;
	}

	public DefaultMutableTreeNode getSubArbol() {
		DefaultMutableTreeNode nodo = new DefaultMutableTreeNode("factor: "
				+ evaluarTipoResultante());
		if (factor != null) {
			DefaultMutableTreeNode factNod = new DefaultMutableTreeNode(factor
					.getLexema());
			nodo.add(factNod);
		}
		if (expresion != null) {
			DefaultMutableTreeNode expNod = expresion.getSubArbol();
			nodo.add(expNod);
		}
		if (llamada != null) {
			DefaultMutableTreeNode llamNod = new DefaultMutableTreeNode(
					"llamado");
			nodo.add(llamNod);
		}
		return nodo;
	}

	public String evaluarTipoResultante() {
		String tipoResultante = "";
		if (factor != null) {
			if (factor.getTipo() != IDENTIFICADOR) {
				tipoResultante = factor.getTipo();
				return tipoResultante;
			} else {
				String varId = factor.getLexema();
				// primero busca en el ambito local
				for (SimboloCampo i : tablaCampos) {
					if (i.getNombre().getLexema().equals(varId)
							&& i.getAmbito().equals(ambito)) {
						// la variable existe en el ambito actual, entonces
						// obtenemos el tipo
						tipoResultante = i.getTipo().getLexema();
						return tipoResultante;
					}
				}
				// primero busca en el ambito global
				for (SimboloCampo i : tablaCampos) {
					if (i.getNombre().getLexema().equals(varId)) {
						// la variable existe en el ambito global, entonces
						// obtenemos el tipo
						tipoResultante = i.getTipo().getLexema();
						return tipoResultante;
					}
				}
				UtilidadesSemanticas.reportarError("la variable " + varId
						+ " jamas fue declarada");
			}

		}
		if (llamada != null) {
			llamada.setTablaCampos(tablaCampos);
			llamada.setAmbito(ambito);

			String metodoId = llamada.getNombreMetodo().getLexema();
			for (SimboloMetodo i : tablaMetodos) {
				if (i.getNombre().getLexema().equals(metodoId)) {
					// la variable existe en el ambito actual, entonces
					// obtenemos el tipo
					if (!llamada.getParametros().equals(i.getParametros())) {
						UtilidadesSemanticas
								.reportarError("los parametros no coinciden "
										+ llamada.getNombreMetodo());
					}
					tipoResultante = i.getRetorno().getLexema();
					return tipoResultante;
				}
			}
			return tipoResultante;
		}
		if (expresion != null) {
			expresion.setAmbito(ambito);
			expresion.setTablaCampos(tablaCampos);
			tipoResultante = expresion.evaluarTipoResultante();
			return tipoResultante;
		}
		return tipoResultante;
	}

	public void setTablaMetodos(ArrayList<SimboloMetodo> tablaMetodos) {
		this.tablaMetodos = tablaMetodos;

	}

}
